﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Data.Common;
using System.Transactions;
using System.Collections.Specialized;

namespace Demo.Data.Concrete {
	public class Database<T> where T : class
    {
	 	/// <summary>
        /// Get output parameters
        /// </summary>
        /// <param name="db"></param>
        /// <param name="dbCommand"></param>
        /// <param name="outputValues"></param>
        /// <returns>Dictionary<string, object> outputValues</returns>
        public Dictionary<string, object> GetOutputValues(Database db, DbCommand dbCommand, Dictionary<string, object> outputValues)
        {
            if (outputValues != null)
            {
                foreach (var o in outputValues.ToList())
                {
                    outputValues[o.Key] = db.GetParameterValue(dbCommand, o.Key);
                }
            }
            return outputValues;
        }

		 /// <summary>
        /// Execute a stored procedure and return a list data
        /// </summary>
        /// <param name="storedProc"></param>
        /// <param name="createObjectFromReader"></param>
        /// <param name="outputValues"></param>
        /// <param name="param"></param>
        /// <returns>A list data of T</returns>
        public List<T> GetList(string storedProc, Func<IDataReader, T> createObjectFromReader, Dictionary<string, object> outputValues, params object[] param)
        {
            try{
                List<T> lst = new List<T>();
                Database db = DatabaseFactory.CreateDatabase();
                //using (TransactionScope tScope = new TransactionScope())
                {
					DbCommand dbCommand = db.GetStoredProcCommand(storedProc, param);
	                using (IDataReader reader = db.ExecuteReader(dbCommand))
	                {
	                    while (reader.Read())
	                    {
	                        T t = createObjectFromReader.Invoke(reader);
	                        lst.Add(t);
	                    }
	                }
 					outputValues = GetOutputValues(db,dbCommand, outputValues);
					
					//tScope.Complete();					
                }
                return lst;
            }
            catch (Exception ex){
                throw ex;
            }
        }

		 /// <summary>
        /// Execute a stored procedure and return an object
        /// </summary>
        /// <param name="storedProc"></param>
        /// <param name="createObjectFromReader"></param>
        /// <param name="outputValues"></param>
        /// <param name="param"></param>
        /// <returns>An object T</returns>
        public T Get(string storedProc, Func<IDataReader, T> createObjectFromReader, Dictionary<string, object> outputValues, params object[] param)
        {
            try{
                T t = default(T);
                Database db = DatabaseFactory.CreateDatabase();
                //using (TransactionScope tScope = new TransactionScope())
                {
					DbCommand dbCommand = db.GetStoredProcCommand(storedProc, param);
	                using (IDataReader reader = db.ExecuteReader(dbCommand))
	                {
	                    if (reader.Read())
	                    {
	                        t = createObjectFromReader.Invoke(reader);
	                    }
	                }
					outputValues = GetOutputValues(db, dbCommand, outputValues);
					
					//tScope.Complete();
				}
                return t;
            }
            catch (Exception ex){
                throw ex;
            }
        }
		
		/// <summary>
        /// Execute a stored procedure
        /// </summary>
        /// <param name="storedProc"></param>
        /// <param name="createObjectFromReader"></param>
        /// <param name="outputValues"></param>
        /// <param name="param"></param>
        /// <returns>Effected records</returns>
        public int ExecuteNoneQuery(string storedProc, Func<IDataReader, T> createObjectFromReader, Dictionary<string, object> outputValues, params object[] param)
        {
            try{
                int effectedRecords = 0;
                Database db = DatabaseFactory.CreateDatabase();
                using (TransactionScope tScope = new TransactionScope())
                {
					DbCommand dbCommand = db.GetStoredProcCommand(storedProc, param);
	                effectedRecords = db.ExecuteNonQuery(dbCommand);
	                tScope.Complete();
	                
					outputValues = GetOutputValues(db, dbCommand, outputValues);
				}
                return effectedRecords;
            }
            catch (Exception ex){
                throw ex;
            }
        }
        public static bool CheckExistColumn(DataTable dt, string columnName)
        {
            dt.DefaultView.RowFilter = "ColumnName= '" + columnName + "'";
            return (dt.DefaultView.Count > 0);
        }
    }
}
